/*
 * Copyright (c) 2016 moondev.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.moondev.moonlog.example.moonlog.monitor.handler.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import cn.moondev.moonlog.example.moonlog.monitor.dao.SqlMonitorDao;
import cn.moondev.moonlog.example.moonlog.monitor.entity.SqlMonitor;
import cn.moondev.moonlog.example.moonlog.monitor.handler.MonitorMsgHandler;
import cn.moondev.moonlog.example.moonlog.monitor.utils.TableBuilder;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.google.common.base.Splitter;

/**
 * 处理log4jdbc产生的日志，用于监控sql执行时间
 * @date 2016年1月4日
 * @author chensc
 */
@Component("log4jdbcMonitorHandler")
public class Log4jdbcMonitorHandler implements MonitorMsgHandler {
	
	private static final Logger log = LoggerFactory.getLogger(Log4jdbcMonitorHandler.class);
	
	@Autowired
	private SqlMonitorDao dao;
	
    public void handle(List<String> msgList) {
    	List<SqlMonitor> sqlList = processMsgList2SQLMonitorList(msgList);
    	if(sqlList.size() == 0) {
    		return;
    	}
    	try {
    		dao.save(sqlList, TableBuilder.buildSqlMonitorTableName(new DateTime()));
    	}catch(Exception e) {
    		log.error("处理SQL日志出现异常",e);
    	}
    }
    
    /**
     * 日志列表转换成SQLMonitor列表
     * @param msgList
     * @return
     */
    private List<SqlMonitor> processMsgList2SQLMonitorList(List<String> msgList) {
    	List<SqlMonitor> sqls = new ArrayList<SqlMonitor>();
    	for(String msg : msgList) {
			SqlMonitor sm = msg2SQLMonitor(msg);
    		if(sm != null) {
    			sqls.add(sm);
    		}
    	}
    	return sqls;
    }
    
    /**
	 * 对log4jdbc输出日志进行处理
	 * @param msg
	 */
	@SuppressWarnings("unchecked")
	private SqlMonitor msg2SQLMonitor(String msg) {
		SqlMonitor sqlMonitor = new SqlMonitor();
		Map<String,String> map = null;
		try {
			map = JSON.parseObject(msg, HashMap.class);
		}catch(JSONException e) {
			log.error("消息非JSON格式,直接返回,消息内容：{}",msg);
			return null;
		}
		sqlMonitor.setSysname(Objects.toString(map.get("sysName"),""));
		// 2016-01-13 11:10:14.724|29d8f93911204e3989cbb48db2da1064|http-bio-8080-exec-4|INFO |jdbc.sqltiming-select id, app_id, name from app_info where status <> -1  order by create_time desc {executed in 1 msec}
		String logStr = map.get("log");
		List<String> logArr = Splitter.on('|').splitToList(logStr);
		// 设置调用日期
		sqlMonitor.setInvokeDate(logArr.get(0).substring(0, 10));
		sqlMonitor.setInvokeTime(new DateTime(logArr.get(0).replace(" ", "T")).getMillis());
				
		// 设置UUID
		sqlMonitor.setUuid(logArr.get(1));
		
    	String sqlLog = logArr.get(3);
    	// 大括号第一次出现的位置
    	int firstBracePosition = sqlLog.indexOf('{');
    	// 获取执行时间
    	String timeStr = sqlLog.substring(firstBracePosition);
    	timeStr = findNumFromStr(timeStr);
    	int costytime = Integer.parseInt(timeStr);
    	// 判断SQL执行时间是否大于监控阀值,大于阀值监控,小于阀值忽略
    	if(costytime < Integer.valueOf(Objects.toString(map.get("threshold"), "0"))) {
    		return null;
    	}
    	sqlMonitor.setExecutedTime(costytime);
    	// 获取SQL语句
    	String sql = sqlLog.substring(sqlLog.lastIndexOf("|") + 1,firstBracePosition).trim();
    	if(sql.startsWith("-")) {
    		sql = sql.substring(1);
    	}
    	// 去掉jdbc.sqltiming-
    	else if(sql.startsWith("jdbc")) {
    		sql = sql.substring(15);
    	}
    	if(validatorSQL(sql)) {
    		sqlMonitor.setSql(sql.trim());
    	}else{
    		return null;
    	}
		
		return sqlMonitor;
	}

	/**
	 * 简单的检查是否为SQL语句
	 * @param sql
	 * @return
	 */
	private boolean validatorSQL(String sql) {
		return sql.startsWith("select") || sql.startsWith("update") || sql.startsWith("delete")
				|| sql.startsWith("insert");
	}
	
    private String findNumFromStr(String str) {
    	StringBuilder sb = new StringBuilder();
    	for(char ch : str.toCharArray()) {
    		if(ch >= '0' && ch <='9') {
    			sb.append(ch);
    		}
    	}
    	return sb.toString();
    }
}